import 'dart:convert';
import 'dart:io';
import 'dart:isolate';

import 'package:flutter/cupertino.dart';
import 'package:flutter_one/class/appsetting/setting.dart' deferred as setting;
import 'package:http/http.dart' as http;

/*网络请求类*/
class CMRequest {
  //MARK: - 单例
  CMRequest._privateConstructor();

  static final CMRequest _request = CMRequest._privateConstructor();

  static CMRequest get shareInstance => _request;

  //MARK: - 错误信息处理
  ///https://www.jb51.net/article/105163.htm
  String errorHandle(int statusCode, {int? errorCode}) {
    String ems = "请求失败";

    switch (statusCode) {
      case 302:
        ems = "请求被重定向";
        break;

      case 400:
        ems = "用户名或密码错误";
        break;

      case 401:
        ems = "访问没有授权";
        break;

      case 403:
        ems = "没有权限访问";
        break;

      case 404:
        ems = "请求地址不存在";
        break;

      case 405:
        ems = "请求方式不存在";
        break;

      case 408:
      case 504:
        ems = "请求超时,请检查网络或重试";
        break;

      case 500:
        ems = "服务器内部异常,无法完成请求处理";
        break;

      case 507:
        ems = "服务器无法存储完成请求所必须的内容";
        break;

      case 509:
        ems = "服务器达到带宽限制";
        break;

      case 510:
        ems = "获取资源所需要的策略并没有没满足";
        break;
    }

    switch (errorCode) {
      case -1001:
        ems = "请求超时";
        break;

      //token 过期
      case -1011:
      case 3:
      case 9:
        if (statusCode == 400) {
          ems = "用户名或密码错误";
        } else if (statusCode == 401) {
          ems = "身份验证失败";
        }
        break;

      case -32700:
        ems = "类型转换错误";
        break;

      case -32600:
        ems = "无效的请求";
        break;

      case -32601:
        ems = "没有找到方法";
        break;

      case -32602:
        ems = "无效的参数";
        break;

      case -32603:
      case -1009:
      case 8:
        ems = "网络异常，请检查网络";
        break;
    }

    return ems;
  }

  //MARK: - OAuth Password 网络请求
  /// OAuth Password 网络请求
  /// @params String userName 用户名
  /// @params String andPwd 密码
  /// @params Function _successBack(Object responseData) 成功回调
  /// @params Function _failureBlock(String responseString) 失败回调
  void oAuthRequestPasswordFor(String userName, String andPwd,
      {required void Function(Object responseData) successBack,
      required void Function(String responseString) failureBlock}) async {
    await setting.loadLibrary();

    const String strUrl = '.../oauth/token';
    debugPrint("请求地址：$strUrl,参数：$userName,$andPwd");

    String? msg;
    final mapParams = {
      "username": userName,
      "password": andPwd,
      "grant_type": "password",
      "client_id": "",
      "client_secret": ""
    };

    try {
      final http.Response response = await http
          .post(Uri.parse(strUrl), body: mapParams)
          .timeout(setting.K_APP_REQUEST_TIME_OUT);
      msg = errorHandle(response.statusCode);

      if (response.statusCode == HttpStatus.ok) {
        final mapDic = jsonDecode(response.body);
        if (mapDic != null) {
          final String? accessToken = mapDic['k_user_token'] as String;
          if (accessToken == null || accessToken == "") {
            failureBlock("用户名或密码错误");
          } else {
            //请求成功
            successBack(accessToken);
          }
        } else {
          failureBlock('请求token不存在');
        }
      } else {
        failureBlock(msg);
      }
    } catch (e, _) {
      if (e is SocketException) {
        msg = errorHandle(0, errorCode: e.osError?.errorCode);
      }
      debugPrint("请求异常，详见:$e");
      failureBlock(msg ?? e.toString());
    }
  }

  //MARK: - GET请求
  /// GET请求
  /// - Parameters:
  ///   - strUrl: 请求地址
  ///   - paras: 请求参数
  ///   - successBack: 成功回调
  ///   - failureBack: 失败回到
  void getRequestForServerData(String strUrl,
      {Map<String, String>? mapParams,
      required void Function(Object responseData) successBack,
      required void Function(String responseString) failureBlock}) async {
    await setting.loadLibrary();

    if (mapParams != null && mapParams.isNotEmpty) {
      debugPrint("请求地址：$strUrl?$mapParams");
    } else {
      debugPrint("请求地址：$strUrl");
    }

    String? msg;
    try {
      var request = http.MultipartRequest("GET", Uri.parse(strUrl));

      //参数
      if (mapParams != null && mapParams.isNotEmpty) {
        mapParams.forEach((key, value) {
          request.fields[key] = value;
        });
      }

      final response = await request.send();
      msg = errorHandle(response.statusCode);

      if (response.statusCode == HttpStatus.ok) {
        response.stream.bytesToString().then((value) {
          debugPrint(value);
          final mapDic = jsonDecode(value);
          if (mapDic != null) {
            //请求成功
            if (mapDic[setting.K_API_RESULT_CODE2] != null &&
                mapDic[setting.K_API_RESULT_CODE2] as int == 200) {
              successBack(mapDic[setting.K_API_RESULT_DATA2]);
            } else if (setting.K_API_IS_OK(mapDic[setting.K_API_RESULT_CODE])) {
              successBack(mapDic[setting.K_API_RESULT_DATA]);
            } else {
              failureBlock('请求数据不存在');
            }
          } else {
            failureBlock(msg ?? "请求失败");
          }
        });
      } else {
        failureBlock(msg ?? "请求失败");
      }
    } catch (e, _) {
      if (e is SocketException) {
        msg = errorHandle(0, errorCode: e.osError?.errorCode);
      }
      debugPrint("请求异常，详见:$e");
      failureBlock(msg ?? e.toString());
    }
  }

  //MARK: - POST请求
  /// - Parameter strUrl: 请求地址
  /// - Parameter paras: 请求参数
  /// - Parameter headers: 请求头
  /// - Parameter successBack: 成功回调
  /// - Parameter failureBack: 失败回调
  void postRequestWithParamsFor(String strUrl,
      {Map<String, dynamic>? mapParams,
      required Map<String, String> headers,
      required void Function(Object responseData) successBack,
      required void Function(String responseString) failureBlock}) async {
    await setting.loadLibrary();
    if (mapParams != null) {
      debugPrint("请求地址：$strUrl?$mapParams");
    } else {
      debugPrint("请求地址：$strUrl");
    }

    String? msg;
    try {
      final http.Response response = await http
          .post(Uri.parse(strUrl), headers: headers, body: mapParams)
          .timeout(setting.K_APP_REQUEST_TIME_OUT);

      msg = errorHandle(response.statusCode);

      if (response.statusCode == HttpStatus.ok) {
        final mapDic = jsonDecode(response.body);
        if (mapDic != null) {
          //请求成功
          if (mapDic[setting.K_API_RESULT_CODE2] != null &&
              mapDic[setting.K_API_RESULT_CODE2] as int == 200) {
            successBack(mapDic[setting.K_API_RESULT_DATA2]);
          } else if (setting.K_API_IS_OK(mapDic[setting.K_API_RESULT_CODE])) {
            successBack(mapDic[setting.K_API_RESULT_DATA]);
          } else {
            failureBlock('请求token不存在');
          }
        } else {
          failureBlock(msg ?? "请求失败");
        }
      } else {
        failureBlock(msg ?? "请求失败");
      }
    } catch (e, _) {
      if (e is SocketException) {
        msg = errorHandle(0, errorCode: e.osError?.errorCode);
      }
      debugPrint("请求异常，详见:$e");
      failureBlock(msg ?? e.toString());
    }
  }

  /// 文件或图片上传
  /// - Parameter strUrl: 请求地址
  /// - Parameter paras: 请求参数
  /// - Parameter headers: 请求头
  /// - Parameter successBack: 成功回调
  /// - Parameter failureBack: 失败回调
  void postImageUploadToServer(String strUrl, List<http.MultipartFile> fms,
      {required void Function(Object responseData) successBack,
      required void Function(String responseString) failureBlock}) async {
    await setting.loadLibrary();
    debugPrint("请求地址：$strUrl");

    String? msg;
    try {
      final request = http.MultipartRequest('POST', Uri.parse(strUrl));
      for (var element in fms) {
        request.files.add(element);
      }

      final response =
          await request.send().timeout(setting.K_APP_REQUEST_TIME_OUT);
      msg = errorHandle(response.statusCode);

      if (response.statusCode == HttpStatus.ok) {
        final mapDic = jsonDecode(response.toString());
        if (mapDic != null) {
          //请求成功
          if (mapDic[setting.K_API_RESULT_CODE2] != null &&
              mapDic[setting.K_API_RESULT_CODE2] as int == 200) {
            successBack(mapDic[setting.K_API_RESULT_DATA2]);
          } else if (setting.K_API_IS_OK(mapDic[setting.K_API_RESULT_CODE])) {
            successBack(mapDic[setting.K_API_RESULT_DATA]);
          } else {
            msg = mapDic[setting.K_API_RESULT_MESSAGE] ?? msg;
            failureBlock(msg ?? "请求失败");
          }
        } else {
          failureBlock(msg);
        }
      } else {
        failureBlock(msg);
      }
    } catch (e, _) {
      if (e is SocketException) {
        msg = errorHandle(0, errorCode: e.osError?.errorCode);
      }
      debugPrint("请求异常，详见:$e");
      failureBlock(msg ?? e.toString());
    }
  }

  //MARK: - PUT请求
  /// PUT请求
  /// - Parameters:
  ///   - strUrl: 请求地址
  ///   - paras: 请求参数
  ///   - successBack: 成功回调
  ///   - failureBack: 失败回到
  void putRequestForServerData(String strUrl,
      {Map<String, String>? mapParams,
      required void Function(Object responseData) successBack,
      required void Function(String responseString) failureBlock}) async {
    await setting.loadLibrary();
    if (mapParams != null) {
      debugPrint("请求地址：$strUrl?$mapParams");
    } else {
      debugPrint("请求地址：$strUrl");
    }

    String? msg;
    try {
      final http.Response response = await http
          .put(Uri.parse(strUrl), headers: mapParams)
          .timeout(setting.K_APP_REQUEST_TIME_OUT);
      msg = errorHandle(response.statusCode);

      if (response.statusCode == HttpStatus.ok) {
        final mapDic = jsonDecode(response.body);
        if (mapDic != null) {
          //请求成功
          if (mapDic[setting.K_API_RESULT_CODE2] != null &&
              mapDic[setting.K_API_RESULT_CODE2] as int == 200) {
            successBack(mapDic[setting.K_API_RESULT_DATA2]);
          } else if (setting.K_API_IS_OK(mapDic[setting.K_API_RESULT_CODE])) {
            successBack(mapDic[setting.K_API_RESULT_DATA]);
          } else {
            failureBlock('请求token不存在');
          }
        } else {
          failureBlock(msg);
        }
      } else {
        failureBlock(msg);
      }
    } catch (e, _) {
      if (e is SocketException) {
        msg = errorHandle(0, errorCode: e.osError?.errorCode);
      }
      debugPrint("请求异常，详见:${e}");
      failureBlock(msg ?? e.toString());
    }
  }

  //MARK: - DELETE请求
  /// DELETE请求
  /// - Parameters:
  ///   - strUrl: 请求地址
  ///   - paras: 请求参数
  ///   - successBack: 成功回调
  ///   - failureBack: 失败回到
  void deleteRequestForServerData(String strUrl,
      {Map<String, String>? mapParams,
      required void Function(Object responseData) successBack,
      required void Function(String responseString) failureBlock}) async {
    await setting.loadLibrary();
    if (mapParams != null) {
      debugPrint("请求地址：$strUrl?$mapParams");
    } else {
      debugPrint("请求地址：$strUrl");
    }

    String? msg;
    try {
      final http.Response response = await http
          .delete(Uri.parse(strUrl), headers: mapParams)
          .timeout(setting.K_APP_REQUEST_TIME_OUT);
      msg = errorHandle(response.statusCode);

      if (response.statusCode == HttpStatus.ok) {
        final mapDic = jsonDecode(response.body);
        if (mapDic != null) {
          //请求成功
          if (mapDic[setting.K_API_RESULT_CODE2] != null &&
              mapDic[setting.K_API_RESULT_CODE2] as int == 200) {
            successBack(mapDic[setting.K_API_RESULT_DATA2]);
          } else if (setting.K_API_IS_OK(mapDic[setting.K_API_RESULT_CODE])) {
            successBack(mapDic[setting.K_API_RESULT_DATA]);
          } else {
            failureBlock('请求token不存在');
          }
        } else {
          failureBlock(msg);
        }
      } else {
        failureBlock(msg);
      }
    } catch (e, _) {
      if (e is SocketException) {
        msg = errorHandle(0, errorCode: e.osError?.errorCode);
      }
      debugPrint("请求异常，详见:$e");
      failureBlock(msg ?? e.toString());
    }
  }

  //MARK: - 多线程
  /// - 获取数据
  static loadReceiveData(SendPort sendPort) async {
    await setting.loadLibrary();

    // Open the ReceivePort for incoming messages.
    ReceivePort port = ReceivePort();

    // Notify any other isolates what port this isolate listens to.
    sendPort.send(port.sendPort);

    await for (var msg in port) {
      final String data = msg[0];
      SendPort replyTo = msg[1];

      final String dataURL = data;
      http.Response response = await http.get(Uri.parse(dataURL));

      final mapDic = jsonDecode(response.body);
      if (mapDic != null) {
        //获取用户信息
        if (mapDic["userAuthentication"] != null &&
            mapDic["userAuthentication"]["details"]["userAuthentication"]
                    ["principal"] !=
                null) {
          replyTo.send(mapDic["userAuthentication"]["details"]
              ["userAuthentication"]["principal"]);
        }
        if (mapDic[setting.K_API_RESULT_CODE2] != null &&
            mapDic[setting.K_API_RESULT_CODE2] as int == 200) {
          final _temp = mapDic[setting.K_API_RESULT_DATA2];

          if (_temp != null) {
            replyTo.send(_temp);
          }
        } else if (setting.K_API_IS_OK(mapDic[setting.K_API_RESULT_CODE])) {
          final _temp = mapDic[setting.K_API_RESULT_DATA];

          if (_temp != null) {
            replyTo.send(_temp);
          }
        }
      }

      // Lots of JSON to parse
      replyTo.send(null);
    }
  }

  Future sendReceive(SendPort port, msg) {
    ReceivePort response = ReceivePort();
    port.send([msg, response.sendPort]);
    return response.first;
  }
}
